﻿using System.CodeDom;
using System.Configuration;
using System.Text.RegularExpressions;

namespace MyCoreLib.Data.SqlClient
{
    using System;
    using System.Data;
    using System.Data.SqlClient;
    using System.Threading;
    using System.Threading.Tasks;
    using Common;

    public class SqlClientObject : DbClientObject
    {
        private readonly SqlConnection Connection;

        private static readonly Regex ConfigConnectionStringNameRegex = new Regex(@"(?six)^\s*name\s*=\s*(?<name>\S+)\s*$");

        private static string GetConnectionString(string connectionStringText)
        {
            var match = ConfigConnectionStringNameRegex.Match(connectionStringText);
            if (match.Success)
            {
                return ConfigurationManager.ConnectionStrings[match.Groups["name"].Value].ConnectionString;
            }
            return connectionStringText;
        }


        public SqlClientObject(string connectionString)
            : this(new SqlConnection(GetConnectionString(connectionString)))
        {
        }

        public SqlClientObject(SqlConnection connection)
            : base(connection)
        {
            if (ReferenceEquals(connection, null))
            {
                throw new ArgumentNullException("connection");
            }
            this.Connection = connection;
        }

        public SqlTransactionObject BeginTransaction()
        {
            return (SqlTransactionObject)base.BeginTransaction();
        }

        public SqlTransactionObject BeginTransaction(IsolationLevel isolationLevel)
        {
            return (SqlTransactionObject)base.BeginTransaction();
        }

        protected sealed override DbTransactionObject CreateTransactionObject(IDbTransaction dbTransaction)
        {
            return new SqlTransactionObject(this, (SqlTransaction)dbTransaction);
        }
        

        public int ExecuteNonQuery(SqlCommand command)
        {
            var cmdConnection = command.Connection;
            var cmdTransaction = command.Transaction;
            try
            {
                command.Connection = this.Connection;
                command.Transaction = (SqlTransaction)this.GetInnerTransaction();
                using (OpenConnection())
                {
                    return command.ExecuteNonQuery();
                }
            }
            finally
            {
                command.Connection = cmdConnection;
                command.Transaction = cmdTransaction;
            }
        }

        private async Task<IDisposable> OpenConnectionAsync(CancellationToken token)
        {
            await Connection.OpenAsync(token);
            return Disposable.Create(this.Connection.Close);
        }

        public async Task<int> ExecuteNonQueryAsync(SqlCommand command, CancellationToken token)
        {
            using( var connection = (SqlClientObject)this.CreateCopy())
            using (command = command.Clone())
            using (await connection.OpenConnectionAsync(token))
            {                
                return await command.ExecuteNonQueryAsync(token);
            }                       
        }

        protected override IDbClientObject CreateCopy()
        {
            return new SqlClientObject(this.Connection.ConnectionString);
        }

    }
}
